﻿//
// Copyright 2024 Exhunter Technology Co.Ltd2.
//

namespace X18.Framework.Core.Hash
{
    /// <summary>
    /// Crc64算法
    /// </summary>
    public static class Crc64
    {
        private static readonly ulong[] table = new ulong[256];
        private const ulong poly = 0xc96c5795d7870f42ul; // 0x42F0E1EBA9EA3693 bit reversed

        static Crc64()
        {
            for (ulong i = 0; i < (ulong)table.Length; i++)
            {
                ulong crc = i;
                for (int j = 0; j < 8; j++)
                {
                    crc = (crc & 1ul) == 1ul ? poly ^ (crc >> 1) : (crc >> 1);
                }
                table[i] = crc;
            }
        }

        public static ulong ComputeHashToInt64(string data)
        {
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(data);
            ulong result = ComputeHashToInt64(bytes);
            return result;
        }

        public static ulong ComputeHashToInt64(byte[] data)
        {
            ulong crc = 0xfffffffffffffffful;
            for (int i = 0; i < data.Length; i++)
            {
                byte index = (byte)((crc & 0xff) ^ data[i]);
                crc = (crc >> 8) ^ table[index];
            }
            return ~crc;
        }

        public static string ComputeHashToString(string data)
        {
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(data);
            byte[] buffer = ComputeHashToBytes(bytes);
            string result = BitConverter.ToString(buffer);
            return result;
        }

        public static string ComputeHashToString(byte[] data)
        {
            byte[] buffer = ComputeHashToBytes(data);
            string result = BitConverter.ToString(buffer);
            return result;
        }

        public static byte[] ComputeHashToBytes(string data)
        {
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(data);
            byte[] result = ComputeHashToBytes(bytes);
            return result;
        }

        public static byte[] ComputeHashToBytes(byte[] data)
        {
            ulong uhash = ComputeHashToInt64(data);
            byte[] result = new byte[8];
            for (int i = 0; i < 8; i++)
            {
                result[i] = (byte)((uhash >> ((7 - i) * 8)) & 0xff);
            }
            return result;
        }
    }
}
